/*
 * Configuration.java
 *
 * Created on June 18, 2007, 3:01 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.atomojo.auth.service;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.infoset.xml.Document;
import org.infoset.xml.DocumentLoader;
import org.infoset.xml.Element;
import org.infoset.xml.InfosetFactory;
import org.infoset.xml.ItemConstructor;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.Name;
import org.infoset.xml.XMLException;
import org.infoset.xml.sax.SAXDocumentLoader;

/**
 *
 * @author alex
 */
public class Configuration
{
   public static final URI NAMESPACE = URI.create("http://www.atomojo.org/Vocabulary/Auth/Service/2007/1/0");
   static final Name SERVER = Name.create(NAMESPACE,"server");
   static final Name INTERFACE = Name.create(NAMESPACE,"interface");
   static final Name HOST = Name.create(NAMESPACE,"host");
   static final Name KEYSTORE = Name.create(NAMESPACE,"keystore");

   public static class Interface {
      String addr;
      int port;
      boolean secure;
      Map<String,Host> hosts;
      
      public Interface(String addr,int port,boolean secure)
      {
         this.addr = addr;
         this.port = port;
         this.secure = secure;
         this.hosts = new HashMap<String,Host>();
      }
      
      public String getAddress() {
         return addr;
      }
      
      public int getPort() {
         return port;
      }
      
      public boolean isSecure() {
         return secure;
      }
      
      public Map<String,Host> getHosts() {
         return hosts;
      }
      
   }
   
   public static class Host {
      String name;
      String port;
      
      public Host(String name,String hostPort)
      {
         this.name = name;
         this.port = hostPort;
      }
      
      public String getName() {
         return name;
      }

      public String getPort() {
         return port;
      }

   }
   
   List<Interface> interfaces;
   File keyStorePath;
   String keyStorePassword;
   String keyPassword;
   
   /** Creates a new instance of Configuration */
   public Configuration()
   {
      this.interfaces = new ArrayList<Interface>();
   }
   
   public void load(URI location)
      throws IOException,XMLException
   {
      DocumentLoader loader = new SAXDocumentLoader();
      Document doc = loader.load(location);
      Element top = doc.getDocumentElement();
      if (!top.getName().equals(SERVER)) {
         throw new XMLException("Expecting "+SERVER+" but found "+top.getName());
      }
      
      Element keyStoreE = top.getFirstElementNamed(KEYSTORE);
      if (keyStoreE!=null) {
         URI fileRef = keyStoreE.getBaseURI().resolve(keyStoreE.getAttributeValue("href"));
         this.keyStorePath = new File(fileRef.getSchemeSpecificPart());
         this.keyStorePassword = keyStoreE.getAttributeValue("password");
         this.keyPassword = keyStoreE.getAttributeValue("key-password");
      }
      
      Iterator<Element> interfaceElements = top.getElementsByName(INTERFACE);
      while (interfaceElements.hasNext()) {
         Element interfaceE = interfaceElements.next();
         String addr = interfaceE.getAttributeValue("address");
         String portS = interfaceE.getAttributeValue("port");
         boolean secure = interfaceE.getAttributeValue("secure")==null || "true".equals(interfaceE.getAttributeValue("secure"));
         int port = portS==null ? (secure ? 443 : 80) : Integer.parseInt(portS);
         Interface iface = new Interface(addr,port,secure);
         interfaces.add(iface);
         Iterator<Element> hostElements = interfaceE.getElementsByName(HOST);
         while (hostElements.hasNext()) {
            Element hostE = hostElements.next();
            String name = hostE.getAttributeValue("name");
            String hostPort = hostE.getAttributeValue("port");
            Host host = new Host(name,hostPort);
            iface.getHosts().put(name,host);
         }
      }
      
   }
   
   public void store(URI baseURI,ItemDestination dest)
      throws XMLException
   {
      String baseURIValue = baseURI.toString();
      URI baseDir = URI.create(baseURIValue.substring(0,baseURIValue.lastIndexOf('/')+1));
      ItemConstructor constructor = InfosetFactory.getDefaultInfoset().createItemConstructor();
      dest.send(constructor.createDocument(baseURI));
      dest.send(constructor.createElement(SERVER));
      dest.send(constructor.createCharacters("\n"));
      
      Element keystoreE = constructor.createElement(KEYSTORE);
      keystoreE.setAttributeValue("href",baseDir.relativize(keyStorePath.toURI()).toString());
      keystoreE.setAttributeValue("password",keyStorePassword);
      if (!keyStorePassword.equals(keyPassword)) {
         keystoreE.setAttributeValue("key-password",keyPassword);
      }
      dest.send(keystoreE);
      dest.send(constructor.createElementEnd(KEYSTORE));
      dest.send(constructor.createCharacters("\n"));
      
      for (Interface iface : interfaces) {

         Element ifaceE = constructor.createElement(INTERFACE);
         ifaceE.setAttributeValue("address",iface.getAddress());
         ifaceE.setAttributeValue("port",Integer.toString(iface.getPort()));
         ifaceE.setAttributeValue("secure",iface.isSecure() ? "true" : "false");
         dest.send(ifaceE);

         for (Host host : iface.getHosts().values()) {

            Element hostE = constructor.createElement(HOST);
            hostE.setAttributeValue("name",host.getName());
            dest.send(hostE);
            dest.send(constructor.createElementEnd(HOST));
            dest.send(constructor.createCharacters("\n"));
         }

         dest.send(constructor.createElementEnd(INTERFACE));
         dest.send(constructor.createCharacters("\n"));
      }

      dest.send(constructor.createElementEnd(SERVER));
      dest.send(constructor.createDocumentEnd());
   }
   
   public File getKeyStorePath()
   {
      return keyStorePath;
   }
   
   public String getKeyStorePassword()
   {
      return keyStorePassword;
   }
   
   public List<Interface> getInterfaces() {
      return interfaces;
   }

   public void setKeyStorePath(File keyStorePath)
   {
      this.keyStorePath = keyStorePath;
   }

   public void setKeyStorePassword(String keyStorePassword)
   {
      this.keyStorePassword = keyStorePassword;
   }
   
   public void setKeyPassword(String keyPassword)
   {
      this.keyPassword = keyPassword;
   }
   
}
